

package com.kimo.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.kimo.shop.bean.model.Category;
import com.kimo.shop.bean.model.CategoryLang;
import com.kimo.shop.bean.param.CategoryScoreConfigParam;
import com.kimo.shop.bean.param.ScoreConfigParam;
import com.kimo.shop.common.config.Constant;
import com.kimo.shop.common.exception.KimoShopBindException;
import com.kimo.shop.common.i18n.I18nMessage;
import com.kimo.shop.common.i18n.LanguageEnum;
import com.kimo.shop.config.ShopConfig;
import com.kimo.shop.dao.CategoryBrandMapper;
import com.kimo.shop.dao.CategoryMapper;
import com.kimo.shop.dao.CategoryPropMapper;
import com.kimo.shop.dao.ProductMapper;
import com.kimo.shop.service.CategoryLangService;
import com.kimo.shop.service.CategoryService;
import com.kimo.shop.service.SysConfigService;
import lombok.AllArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * @author kimo-taozhouchuan
 */
@Service
@AllArgsConstructor
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService{

	private final CategoryMapper categoryMapper;
	private final ProductMapper productMapper;
	private final CategoryBrandMapper categoryBrandMapper;
	private final ShopConfig shopConfig;

	private final CategoryPropMapper categoryPropMapper;

	private SysConfigService sysConfigService;
	private final CategoryLangService categoryLangService;

	@Override
	@Cacheable(cacheNames = "CategoryListByParentId", key = "#parentId + ':' + #dbLang")
	public List<Category> listByParentId(Long parentId, Integer dbLang) {
		List<Category> categoriesTwo = categoryMapper.listByParentId(parentId, I18nMessage.getDbLang());
		List<Category> categoriesThree = categoryMapper.listThreeByParentId(parentId, I18nMessage.getDbLang());
		for (Category category : categoriesThree) {
			category.setPic(shopConfig.getDomain().getResourcesDomainName() + "/" + category.getPic());
			category.setIcon(shopConfig.getDomain().getResourcesDomainName() + "/" + category.getIcon());
		}
		//根据父类id分组，并放入对应得父类中
		if(CollectionUtils.isNotEmpty(categoriesThree) && CollectionUtils.isNotEmpty(categoriesTwo)){
			Map<Long, List<Category>> categoryMap = categoriesThree.stream().collect(groupingBy(Category::getParentId));
			// 无三级分类的一级分类id集合
			Set<Long> categoryIds = new HashSet<>();
			for (Category category : categoriesTwo) {
				if(categoryMap.containsKey(category.getCategoryId())){
					List<Category> categories = categoryMap.get(category.getCategoryId());
					category.setCategories(categories);
				} else {
					categoryIds.add(category.getCategoryId());
				}
			}
			categoriesTwo = categoriesTwo.stream().filter(item -> !categoryIds.contains(item.getCategoryId())).collect(Collectors.toList());
		}
		return categoriesTwo;
//		return categoryMapper.listByParentId(parentId);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	@Caching(evict = {
			@CacheEvict(cacheNames = "CategoryListByParentId", key = "#category.superiorId"),
			@CacheEvict(cacheNames = "CategoryListByParentId", key = "#category.parentId")
	})
	public void saveCategroy(Category category) {
		category.setRecTime(new Date());
		// 保存分类信息
		categoryMapper.insert(category);
		saveCategoryLang(category);
		insertBrandsAndAttributes(category);

		if (Objects.equals(category.getParentId(),Constant.CATEGORY_ID)){
			this.changeScoreConfig();
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	@Caching(evict = {
			@CacheEvict(cacheNames = "CategoryListByParentId", key = "#category.superiorId"),
			@CacheEvict(cacheNames = "CategoryListByParentId", key = "#category.parentId")
	})
	public void updateCategroy(Category category) {
		Category categoryDB = categoryMapper.selectById(category.getCategoryId());
		category.setUpdateTime(new Date());
		// 保存分类信息
		categoryMapper.updateById(category);
		// 更新分类语言表
		updateCategoryLang(category);
		if (Objects.equals(categoryDB.getStatus(),1) && Objects.equals(category.getStatus(),0)){
			List<Long> ids = new ArrayList<>();
			ids.add(category.getCategoryId());
			List<Category> categoryList = categoryMapper.selectList(new LambdaQueryWrapper<Category>().eq(Category::getParentId, category.getCategoryId()));
			// 如果是平台且不是第三级分类的情况下，还需进行查找子集操作
			if (CollectionUtils.isNotEmpty(categoryList) && categoryDB.getGrade() < 2){
				categoryList.forEach(item -> item.setStatus(0));
				// 获取所有的下级分类,将他们的子集全部下架
				List<Long> offlineIds = new ArrayList<>();
				for (Category categoryByParentId: categoryList){
					categoryByParentId.setStatus(0);
					offlineIds.add(categoryByParentId.getCategoryId());
				}
				// 如果下架的是一级分类，还需进行查找子集操作
				if(Objects.equals(category.getParentId(), 0L)){
					List<Category> childCategories = list(new LambdaQueryWrapper<Category>().in(Category::getParentId, offlineIds));
					if(CollectionUtils.isNotEmpty(childCategories) && categoryDB.getGrade() < 1) {
						for (Category childCategory : childCategories) {
							ids.add(childCategory.getCategoryId());
							childCategory.setStatus(0);
						}
						categoryList.addAll(childCategories);
					}
				}else{
					// 如果下架的是二级分类，直接放入下级分类id进行下架即可
					ids.addAll(offlineIds);
				}
				updateBatchById(categoryList);
			}
			//从正常改为下线
			// 批量修改已经下架的分类下的商品的状态
			if(CollectionUtils.isNotEmpty(ids)) {
				//从正常改为下线
				productMapper.offlineProdByCategoryId(ids);
			}
		}

		//修改积分配置中的分类数据
		if (!Objects.equals(category.getCategoryName(),category.getOldCategoryName())){
			this.changeScoreConfig();
		}
		// 先删除后增加
		deleteBrandsAndAttributes(category.getCategoryId());
		insertBrandsAndAttributes(category);

		// 如果以前有图片，并且图片与现在不同，则删除以前的图片
//		if (StrUtil.isNotBlank(dbCategory.getPic()) && !dbCategory.getPic().equals(category.getPic())) {
//			attachFileService.deleteFile(dbCategory.getPic());
//		}
	}
	private void updateCategoryLang(Category category) {
		Long categoryId = category.getCategoryId();
		String categoryName = category.getCategoryName();
		String categoryNameEn = category.getCategoryNameEn();
		categoryLangService.update(new LambdaUpdateWrapper<CategoryLang>()
				.set(CategoryLang::getCategoryName, categoryName)
				.eq(CategoryLang::getLang, LanguageEnum.LANGUAGE_ZH_CN.getLang())
				.eq(CategoryLang::getCategoryId, categoryId));
		categoryLangService.update(new LambdaUpdateWrapper<CategoryLang>()
				.set(CategoryLang::getCategoryName, StrUtil.isNotBlank(categoryNameEn)?categoryNameEn:categoryName)
				.eq(CategoryLang::getLang, LanguageEnum.LANGUAGE_EN.getLang())
				.eq(CategoryLang::getCategoryId, categoryId));
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	@Caching(evict = {
			@CacheEvict(cacheNames = "CategoryListByParentId", key = "#category.superiorId"),
			@CacheEvict(cacheNames = "CategoryListByParentId", key = "#category.parentId")
	})
	public void deleteCategroy(Category category) {
		categoryMapper.deleteById(category.getCategoryId());
		// 删除分类语言表
		removeCategoryLang(category);
		//修改积分配置中的分类数据
		if (Objects.equals(category.getParentId(), Constant.CATEGORY_ID)){
			this.changeScoreConfig();
		}
		deleteBrandsAndAttributes(category.getCategoryId());
//		if (StrUtil.isNotBlank(category.getPic())) {
//			attachFileService.deleteFile(category.getPic());
//		}
	}
	private void removeCategoryLang(Category category) {
		Long categoryId = category.getCategoryId();
		categoryLangService.remove(new LambdaUpdateWrapper<CategoryLang>().eq(CategoryLang::getCategoryId,categoryId));
	}

	@Override
	@CacheEvict(cacheNames = "CategoryListByParentId", key = "#parentId + ':' + #lang")
	public void removeCacheByParentIdAndLang(Long parentId, Integer lang) {

	}
	@Override
	public Long getParentCategoryByParentId(Long parentId) {
		return categoryMapper.getParentCategoryByParentId(parentId);
	}
	@Override
	public List<Category> categoryList(Category category) {
		return categoryMapper.categoryList(category);
	}

	@Override
	public List<Category> listByLang(Integer lang, Integer maxGrade, Long parentId, Integer status,Long shopId) {
		return categoryMapper.listByLang(lang,maxGrade,parentId,status,shopId);
	}

	@Override
	public Integer getCategoryName(Category category) {
		return categoryMapper.getCategoryName(category);
	}

	@Override
	public Category getCategoryByCategoryId(Long categoryId) {
		return categoryMapper.getCategory(categoryId);
	}

	private void saveCategoryLang(Category category) {
		List<CategoryLang> categoryLangs = new ArrayList<>();
		Long categoryId = category.getCategoryId();
		String categoryName = category.getCategoryName();
		String categoryNameEn = category.getCategoryNameEn();
		// 中文分类
		CategoryLang categoryLang = new CategoryLang();
		categoryLang.setCategoryId(categoryId);
		categoryLang.setLang(LanguageEnum.LANGUAGE_ZH_CN.getLang());
		categoryLang.setCategoryName(categoryName);
		categoryLangs.add(categoryLang);
		// 英文分类
		CategoryLang categoryLangEn = new CategoryLang();
		categoryLangEn.setCategoryId(categoryId);
		categoryLangEn.setLang(LanguageEnum.LANGUAGE_EN.getLang());
		categoryLangEn.setCategoryName(StrUtil.isNotBlank(categoryNameEn) ? categoryNameEn: categoryName);
		categoryLangs.add(categoryLangEn);

		categoryLangService.saveBatch(categoryLangs);
	}

	private void deleteBrandsAndAttributes(Long categoryId) {
		// 删除所有分类所关联的品牌
		categoryBrandMapper.deleteByCategoryId(categoryId);
		// 删除所有分类所关联的参数
		categoryPropMapper.deleteByCategoryId(categoryId);
	}

	private void insertBrandsAndAttributes(Category category) {
		//保存分类与品牌信息
		if(CollUtil.isNotEmpty(category.getBrandIds())){
			categoryBrandMapper.insertCategoryBrand(category.getCategoryId(), category.getBrandIds());
		}

		//保存分类与参数信息
		if(CollUtil.isNotEmpty(category.getAttributeIds())){
			categoryPropMapper.insertCategoryProp(category.getCategoryId(), category.getAttributeIds());
		}
	}

	/**
	 * 刷新积分配置中的分类数据
	 */
	private void changeScoreConfig(){
		ScoreConfigParam scoreParamDb = sysConfigService.getSysConfigObject(Constant.SCORE_CONFIG,ScoreConfigParam.class);
		if (Objects.isNull(scoreParamDb)){
			throw new KimoShopBindException("请先前往 【会员管理】-> 【积分成长值配置】-> 【积分获取配置】 进行配置并保存 ");
		}
		//判断分类数据是否正确
		List<Category> categoryList = categoryMapper.selectList(new LambdaQueryWrapper<Category>()
				.eq(Category::getParentId,Constant.CATEGORY_ID)
				.orderByAsc(Category::getCategoryId)
		);
		Map<Long,Category> categoryMap = categoryList.stream().collect(Collectors.toMap(Category::getCategoryId, category -> category));
		// 没有分类数据时，scoreParamDb.getCategoryConfigs()为null,所以为它new一个对象
		if (Objects.isNull(scoreParamDb.getCategoryConfigs())) {
			scoreParamDb.setCategoryConfigs(Lists.newArrayList());
		}
		//更新数据并去除删除的数据
		Iterator<CategoryScoreConfigParam> iterator = scoreParamDb.getCategoryConfigs().iterator();
		while (iterator.hasNext()){
				CategoryScoreConfigParam categoryScoreConfigParam = iterator.next();
				Category category = categoryMap.get(categoryScoreConfigParam.getCategoryId());
				if (Objects.isNull(category)){
					iterator.remove();
				}else {
					//刷新分类名称
					categoryScoreConfigParam.setCategoryName(category.getCategoryName());
					//删除map中已进行操作过的分类
					categoryMap.remove(categoryScoreConfigParam.getCategoryId());
				}
			}
		// 获取map中剩下的分类的id（剩下的分类为积分配置json中所没有的分类，需要新增）
		Set<Long> longs = categoryMap.keySet();
		// 新增积分配置json中的分类数据
		for (Long catrgoryId:longs){
			Category category = categoryMap.get(catrgoryId);
			CategoryScoreConfigParam categoryScoreConfigParam = new CategoryScoreConfigParam();
			categoryScoreConfigParam.setCategoryId(category.getCategoryId());
			categoryScoreConfigParam.setCategoryName(category.getCategoryName());
			categoryScoreConfigParam.setGetScoreLimit(1.00);
			categoryScoreConfigParam.setUseScoreLimit(1.00);
			scoreParamDb.getCategoryConfigs().add(categoryScoreConfigParam);
		}
		//保存数据
		sysConfigService.saveOrUpdateSysConfigService(scoreParamDb,Constant.SCORE_CONFIG);
	}

}
